<?php
/**
 * Created by PhpStorm.
 * User: root
 * Date: 11/15/18
 * Time: 10:24 AM
 */

namespace caroltc\jenkinsapp\library;


use caroltc\jenkinsapp\util\Http;

class JenkinsSDK
{
    private $url = '';
    private $user_name = '';
    private $password = '';
    private $api_token = '';
    private $auth_password = '';
    private $crumb_field = '';
    private $crumb_value = '';

    public function __construct($url, $user_name, $password, $api_token)
    {
        if (substr($url, -1, 1) == '/') $url = substr($url,0,-1);
        $this->url = $url;
        $this->user_name = $user_name;
        $this->password = $password;
        $this->api_token = $api_token;
        $this->auth_password = empty($password) ? $api_token : $password;
    }

    /**
     * 获取crumb用于请求jenkins设置了CSRF验证的接口
     * @return string
     * @throws \Exception
     */
    private function getCrumb()
    {
        $result = Http::basicAuthGet($this->url .'/crumbIssuer/api/json', $this->user_name, $this->auth_password);
        $data = json_decode($result, true);
        if (empty($data) || !isset($data['crumb']) || !isset($data['crumbRequestField'])) {
            throw new \Exception('无法获取crumb信息，请检查帐号配置. msg:' . $result);
        }
        $this->crumb_field =  $data['crumbRequestField'];
        $this->crumb_value =  $data['crumb'];
        return "{$this->crumb_field}:{$this->crumb_value}";
    }

    /**
     * 登录Crumb接口来获取version(在header里面)
     * @return string
     * @throws \Exception
     */
    public function getJenkinsVersion()
    {
        $result = Http::basicAuthGetAndReturnHeader($this->url .'/crumbIssuer/api/json', $this->user_name, $this->auth_password);
        $headers = $result['header'];
        $version = '';
        foreach ($headers as $header) {
            if (strpos($header, 'X-Jenkins') === 0) {
                $str_arr = explode(':', $header);
                $version = $str_arr[1];
                break;
            }
        }
        if (empty($version)) {
            throw new \Exception('站点配置或帐号信息有误，无法验证jenkins服务器');
        }
        return $version;
    }

    /**
     * 获取jenkins job列表
     * @return array
     * @throws \Exception
     */
    public function getJobList()
    {
        $params = ['tree' => 'jobs[name,color]'];
        $result = Http::basicAuthGet($this->url .'/api/json', $this->user_name, $this->auth_password, $params);
        if (strpos($result, 'Invalid password/token') !== false) {
            throw new \Exception('jenkins授权失败，请检查用户名/password/api_token');
        }
        $data = json_decode($result, true);
        if (empty($data) || !isset($data['jobs'])) {
            throw new \Exception('无法获取jobs信息. msg:' . $result);
        }
        return $data;
    }

    /**
     * 获取job详情
     * @param $job_name
     * @return mixed
     * @throws \Exception
     */
    public function getJobDetail($job_name)
    {
        $result = Http::basicAuthGet($this->url ."/job/{$job_name}/api/json", $this->user_name, $this->auth_password);
        if (strpos($result, 'Error 404 Not Found') !== false) {
            throw new \Exception('无法获取job详细信息. 请检查job名称是否正确');
        }
        $data = json_decode($result, true);
        if (empty($data) || !isset($data['builds'])) {
            throw new \Exception('无法获取job详细信息. msg:' . $result);
        }
        return $data;
    }

    /**
     * build job
     * @param $job_name
     * @param $params
     * @return mixed
     * @throws \Exception
     */
    public function buildJob($job_name, $params = [])
    {
        $crumb_header = $this->getCrumb();
        $header = [];
        if (!empty($crumb_header)) {
            $header[] = $crumb_header;
        }
        $build_path = empty($params) ? 'build' : 'buildWithParameters';
        $result = Http::basicAuthPost($this->url ."/job/{$job_name}/{$build_path}", $this->user_name, $this->auth_password, [], $params, $header);
        if (strpos($result, 'Error 404 Not Found') !== false) {
            throw new \Exception('构建失败，请检查job名称.');
        }
        if (strpos($result, 'Error 400 Nothing is submitted') !== false) {
            throw new \Exception('构建失败，构建参数缺失.');
        }
        if (strpos($result, 'Access Denied') !== false) {
            throw new \Exception('构建失败，无执行权限.');
        }
        if (strpos($result, 'Error') !== false) {
            throw new \Exception('构建失败，系统错误. msg:' . $result);
        }
        return true;
    }

    /**
     * stop job
     * @param $job_name
     * @param $history_number
     * @return bool
     */
    public function stopJob($job_name, $history_number)
    {
        $crumb_header = $this->getCrumb();
        $header = [];
        if (!empty($crumb_header)) {
            $header[] = $crumb_header;
        }
        return Http::basicAuthPost($this->url ."/job/{$job_name}/{$history_number}/stop", $this->user_name, $this->auth_password, [], [], $header);
    }

    /**
     * 获取job build 指定历史详情
     * @param $job_name
     * @param $history_number
     * @return mixed
     * @throws \Exception
     */
    public function getJobBuildHistory($job_name, $history_number)
    {
        $result = Http::basicAuthGet($this->url ."/job/{$job_name}/{$history_number}/api/json", $this->user_name, $this->auth_password);
        if (strpos($result, 'Error 404 Not Found') !== false) {
            throw new \Exception('该build history不存在.');
        }
        if (strpos($result, 'Error 403') !== false) {
            throw new \Exception('该build history详情，服务器认证失败. msg:' . $result);
        }
        $data = json_decode($result, true);
        if (empty($data) || !isset($data['displayName'])) {
            throw new \Exception('获取build history详情失败. msg:' . $result);
        }
        return $data;
    }
}